﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

using Eforcity.Common35;
using Eforcity.Data.Common35;
using Eforcity.EbayApi.BMID;
using Eforcity.EbayApiDb;


namespace Eforcity.EbayApi
{
    public class EbayBMApi
    {
        #region

        private const int _RetrySleepTime = 5000; //(5sec)
        private int _ApiMaxRetry = 5; //(per call)
        private string _ApiEndPoint = string.Empty;
        private int _ApiTimeoutSecond = 60;
        private ConnectionStringSettings _EbayApiDbConn;
        private EbayCredentialsType _Credentials;

        //For Renew Credential        
        private bool _UseSpecificSellerId = false;
        private bool _AllowNonSpecificCredential = false;

        private int _SellerId = -1;
        private int _SessionCallLimit = 100;
        private int _SessionCallCount = 0;
        private int _MinmumCallAvali = 0;

        public EbayBMApi(string apiEndPoint, int apiTimeoutSecond, int apiMaxRetry, int sessionCallLimit, int minCallAvail, ConnectionStringSettings ebayApiDbConn)
        {
            _EbayApiDbConn = ebayApiDbConn;
            _ApiEndPoint = apiEndPoint;
            _ApiTimeoutSecond = apiTimeoutSecond;
            _ApiMaxRetry = apiMaxRetry;
            _SessionCallLimit = sessionCallLimit;
            _UseSpecificSellerId = false;
            _AllowNonSpecificCredential = true;
            _MinmumCallAvali = minCallAvail;
            RenewCredentials();
        }
        public EbayBMApi(string apiEndPoint, int apiTimeoutSecond, int apiMaxRetry, int sessionCallLimit, int minCallAvail, int sellerId,
            bool allowNonSpecificCredential, ConnectionStringSettings ebayApiDbConn)
        {
            _EbayApiDbConn = ebayApiDbConn;
            _ApiEndPoint = apiEndPoint;
            _ApiTimeoutSecond = apiTimeoutSecond;
            _ApiMaxRetry = apiMaxRetry;
            _SessionCallLimit = sessionCallLimit;
            _SellerId = sellerId;
            _UseSpecificSellerId = true;
            _AllowNonSpecificCredential = allowNonSpecificCredential;
            _MinmumCallAvali = minCallAvail;
            RenewCredentials();
        }

        public void Dispose()
        {
            if (_EbayApiDbConn != null)
            {
                _EbayApiDbConn = null;
            }
            GC.Collect();
        }

        private void RenewCredentials()
        {
            _Credentials = null;
            if (_UseSpecificSellerId)
            {
                _Credentials = EbayCredentialsData.GetEbayCredentials(_SellerId, false, _MinmumCallAvali, _EbayApiDbConn);
            }
            else
            {
                _Credentials = EbayCredentialsData.GetEbayCredentials(false, _MinmumCallAvali, _EbayApiDbConn);
            }

            //If The Key Allow NonSpecific, Have a 2nd try
            if (_Credentials == null && _AllowNonSpecificCredential)
            {
                _Credentials = EbayCredentialsData.GetEbayCredentials(false, _MinmumCallAvali, _EbayApiDbConn);
            }

            //See if the key still valid, or any key availabe
            if (_Credentials == null)
            {
                throw new Exception("No Credentials Key Available");
            }
        }
        private void UpdateSessionCallCount()
        {
            _SessionCallCount++;
            if (_SessionCallCount >= _SessionCallLimit)
            {
                RenewCredentials();
                //Reset call count
                _SessionCallCount = 0;
            }
        }
        private TResponse GetApiResponse<TRequest, TResponse>(TRequest request, string callName)
        {
            string requestXml = XmlUtility.SerializeToString(request, true);
            string responseXml = string.Empty;

            TResponse response = default(TResponse);
            int retryCount = 0;
            while (retryCount <= _ApiMaxRetry)
            {
                try
                {
                    responseXml = EbayBMApiUtility.GetApiResponse(requestXml, callName, _Credentials.AuthToken, _ApiEndPoint, _ApiTimeoutSecond);
                    response = (TResponse)XmlUtility.Deserialize(responseXml, typeof(TResponse));
                    break;
                }
                catch (Exception ex)
                {
                    if (retryCount >= _ApiMaxRetry)
                    {
                        throw ex;
                    }
                }
                finally
                {
                    retryCount++;
                }
            }
            if (response == null)
            {
                throw new Exception(
                    "Cannot Deserialize the response xml.\r\n"
                    + "---Response Xml---\r\n"
                    + responseXml);
            }

            return response;
        }

        #endregion

        public GetBestMatchItemDetailsResponse GetBestMatchItemDetails(List<string> itemIdList)
        {
            string callName = "getBestMatchItemDetails";

            GetBestMatchItemDetailsRequest request = new GetBestMatchItemDetailsRequest();
            request.itemId = itemIdList.ToArray();

            try
            {
                GetBestMatchItemDetailsResponse response = GetApiResponse<GetBestMatchItemDetailsRequest, GetBestMatchItemDetailsResponse>(request, callName);

                return response;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public FindBestMatchItemDetailsAdvancedResponse FindBestMatchItemDetailsAdvanced(List<string> itemIdList, string keywords, string categoryId, bool ignoreFeatured, int siteResultsPerPage, bool withBestMatchData)
        {
            string callName = "findBestMatchItemDetailsAdvanced";

            FindBestMatchItemDetailsAdvancedRequest request = new FindBestMatchItemDetailsAdvancedRequest();
            request.siteResultsPerPage = siteResultsPerPage;
            if (withBestMatchData)
            {
                request.outputSelector = new BestMatchOutputSelectorType[] { BestMatchOutputSelectorType.FirstPageSummary, BestMatchOutputSelectorType.SellerInfo };
            }
            else
            {
                request.outputSelector = new BestMatchOutputSelectorType[] { BestMatchOutputSelectorType.FirstPageSummary };
            }
            if (itemIdList != null && itemIdList.Count > 0)
            {
                request.postSearchItemFilter = itemIdList.ToArray();
            }
            if (!string.IsNullOrEmpty(keywords))
            {
                request.keywords = keywords;
            }
            if (!string.IsNullOrEmpty(categoryId))
            {
                request.categoryId = categoryId;
            }
            request.ignoreFeaturedSpecified = true;
            request.ignoreFeatured = ignoreFeatured;
            try
            {
                FindBestMatchItemDetailsAdvancedResponse response = GetApiResponse<FindBestMatchItemDetailsAdvancedRequest, FindBestMatchItemDetailsAdvancedResponse>(request, callName);

                return response;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public FindBestMatchItemDetailsByCategoryResponse FindBestMatchItemDetailsByCategory(List<string> sellerList, string categoryId, bool ignoreFeatured, int siteResultsPerPage)
        {
            string callName = "findBestMatchItemDetailsByCategory";

            FindBestMatchItemDetailsByCategoryRequest request = new FindBestMatchItemDetailsByCategoryRequest();
            request.siteResultsPerPage = siteResultsPerPage;
            request.outputSelector = new BestMatchOutputSelectorType[] { BestMatchOutputSelectorType.SellerInfo };

            if (!string.IsNullOrEmpty(categoryId))
            {
                request.categoryId = categoryId;
            }
            if (sellerList != null && sellerList.Count > 0)
            {
                request.postSearchSellerFilter = sellerList.ToArray();
            }

            request.ignoreFeaturedSpecified = true;
            request.ignoreFeatured = ignoreFeatured;
            try
            {
                FindBestMatchItemDetailsByCategoryResponse response = GetApiResponse<FindBestMatchItemDetailsByCategoryRequest, FindBestMatchItemDetailsByCategoryResponse>(request, callName);

                return response;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
